/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "libzlang_stdtypes.h"

struct ZlangDirectProperty_functionptr
{
	struct ZlangObject	*obj ;
	struct ZlangFunction	*func ;
} ;

static int SetFunction( struct ZlangRuntime *rt , struct ZlangObject *in , struct ZlangDirectProperty_functionptr *functionptr_obj_direct_prop )
{
	struct ZlangObject		*in_tostr = NULL ;
	char				*full_func_name = NULL ;
	char				*p = NULL ;
	char				*master_obj_name = NULL ;
	
	int				nret = 0 ;
	
	nret = ToString( rt , in , & in_tostr ) ;
	if( nret )
		return nret;
	
	nret = GetDataPtr( rt , in_tostr , (void**) & full_func_name , NULL ) ;
	if( nret )
		return nret;
	
	p = strchr( full_func_name , '.' ) ;
	if( p == NULL )
	{
		functionptr_obj_direct_prop->obj = NULL ;
		functionptr_obj_direct_prop->func = QueryGlobalFunctionByFullFunctionName( rt , full_func_name ) ;
		if( functionptr_obj_direct_prop->func == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_NOT_FOUND , "global function '%s' not found" , full_func_name )
			return ZLANG_ERROR_FUNC_NOT_FOUND;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "query global function '%s' ok" , full_func_name )
		}
	}
	else
	{
		*(p) = '\0' ;
		master_obj_name = full_func_name ;
		full_func_name = p + 1 ;
		
		functionptr_obj_direct_prop->obj = QueryObjectByObjectName( rt , master_obj_name ) ;
		if( functionptr_obj_direct_prop->obj == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED , "object '%s' not imported or declared" , master_obj_name )
			return ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED;
		}
		
		functionptr_obj_direct_prop->func = QueryFunctionByFullFunctionNameInObject( rt , functionptr_obj_direct_prop->obj , full_func_name ) ;
		if( functionptr_obj_direct_prop->func == NULL )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_NOT_FOUND_IN_OBJECT , "function '%s' not found in object '%s'" , full_func_name , master_obj_name )
			return ZLANG_ERROR_FUNC_NOT_FOUND_IN_OBJECT;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "object '%s' function '%s' found" , master_obj_name , full_func_name )
		}
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_functionptr_GetObjectName;
int ZlangInvokeFunction_functionptr_GetObjectName( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	int					nret = 0 ;
	
	nret = CallRuntimeFunction_string_SetStringValue( rt , out1 , GetObjectName(functionptr_direct_prop->obj) , -1 ) ;
	if( nret )
		return nret;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_functionptr_GetFunctionName;
int ZlangInvokeFunction_functionptr_GetFunctionName( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	int					nret = 0 ;
	
	nret = CallRuntimeFunction_string_SetStringValue( rt , out1 , GetFunctionName(functionptr_direct_prop->func) , -1 ) ;
	if( nret )
		return nret;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_functionptr_GetFullFunctionName;
int ZlangInvokeFunction_functionptr_GetFullFunctionName( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	int					nret = 0 ;
	
	nret = CallRuntimeFunction_string_SetStringValue( rt , out1 , GetFullFunctionName(functionptr_direct_prop->func) , -1 ) ;
	if( nret )
		return nret;
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_functionptr_FindFunction_string;
int ZlangInvokeFunction_functionptr_FindFunction_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	
	int					nret = 0 ;
	
	nret = SetFunction( rt , in1 , GetObjectDirectProperty(out1) ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
	}
	else
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	}
	
	return 0;
}

ZlangInvokeFunction ZlangInvokeFunction_functionptr_SetFunction_string;
int ZlangInvokeFunction_functionptr_SetFunction_string( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	struct ZlangObject			*in1 = GetInputParameterInLocalObjectStack(rt,1) ;
	struct ZlangObject			*out1 = GetOutputParameterInLocalObjectStack(rt,1) ;
	int					nret = 0 ;
	
	nret = SetFunction( rt , in1 , functionptr_direct_prop ) ;
	if( nret )
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , FALSE );
	}
	else
	{
		CallRuntimeFunction_bool_SetBoolValue( rt , out1 , TRUE );
	}
	
	return 0;
}

ZlangCreateDirectPropertyFunction ZlangCreateDirectProperty_functionptr;
void *ZlangCreateDirectProperty_functionptr( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = NULL ;
	
	functionptr_direct_prop = (struct ZlangDirectProperty_functionptr *)ZLMALLOC( sizeof(struct ZlangDirectProperty_functionptr) ) ;
	if( functionptr_direct_prop == NULL )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_ALLOC , "alloc memory for entity" )
		return NULL;
	}
	memset( functionptr_direct_prop , 0x00 , sizeof(struct ZlangDirectProperty_functionptr) );
	
	return (void *)functionptr_direct_prop;
}

ZlangDestroyDirectPropertyFunction ZlangDestroyDirectProperty_functionptr;
void ZlangDestroyDirectProperty_functionptr( struct ZlangRuntime *rt , struct ZlangObject *obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	ZLFREE( functionptr_direct_prop );
	
	return;
}

ZlangToStringFunction ZlangToString_functionptr;
int ZlangToString_functionptr( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject **tostr_obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	char					*full_func_name = NULL ;
	
	full_func_name = GetFullFunctionName(functionptr_direct_prop->func) ;
	if( full_func_name )
	{
		CallRuntimeFunction_string_SetStringValue( rt , (*tostr_obj) , full_func_name , strlen(full_func_name) ) ;
	}
	
	return 0;
}

ZlangFromDataPtrFunction ZlangFromDataPtr_functionptr;
int ZlangFromDataPtr_functionptr( struct ZlangRuntime *rt , struct ZlangObject *obj , void *value_ptr , int32_t value_len )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	if( value_ptr )
	{
		functionptr_direct_prop->func = (struct ZlangFunction *)value_ptr ;
	}
	
	return 0;
}

ZlangGetDataPtrFunction ZlangGetDataPtr_functionptr;
int ZlangGetDataPtr_functionptr( struct ZlangRuntime *rt , struct ZlangObject *obj , void **value_ptr , int32_t *value_len )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	if( value_ptr )
	{
		(*value_ptr) = functionptr_direct_prop->func ;
	}
	
	if( value_len )
	{
		(*value_len) = GetFunctionSize() ;
	}
	
	return 0;
}

ZlangCompareFunction ZlangCompare_functionptr_EGUAL_functionptr;
int ZlangCompare_functionptr_EGUAL_functionptr( struct ZlangRuntime *rt , struct ZlangObject *in_obj1 , struct ZlangObject *in_obj2 , struct ZlangObject *out_obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr1_direct_prop = GetObjectDirectProperty(in_obj1) ;
	struct ZlangDirectProperty_functionptr	*functionptr2_direct_prop = GetObjectDirectProperty(in_obj2) ;
	
	if( functionptr1_direct_prop->func == functionptr2_direct_prop->func )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "[%s]==[%s]=>[true]" , GetFullFunctionName(functionptr1_direct_prop->func) , GetFullFunctionName(functionptr2_direct_prop->func) )
		CallRuntimeFunction_bool_SetBoolValue( rt , out_obj , TRUE );
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "[%s]==[%s]=>[false]" , GetFullFunctionName(functionptr1_direct_prop->func) , GetFullFunctionName(functionptr2_direct_prop->func) )
		CallRuntimeFunction_bool_SetBoolValue( rt , out_obj , FALSE );
	}
	
	return 0;
}

ZlangCompareFunction ZlangCompare_functionptr_NOTEGUAL_functionptr;
int ZlangCompare_functionptr_NOTEGUAL_functionptr( struct ZlangRuntime *rt , struct ZlangObject *in_obj1 , struct ZlangObject *in_obj2 , struct ZlangObject *out_obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr1_direct_prop = GetObjectDirectProperty(in_obj1) ;
	struct ZlangDirectProperty_functionptr	*functionptr2_direct_prop = GetObjectDirectProperty(in_obj2) ;
	
	if( functionptr1_direct_prop->func != functionptr2_direct_prop->func )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "[%s]!=[%s]=>[true]" , GetFullFunctionName(functionptr1_direct_prop->func) , GetFullFunctionName(functionptr2_direct_prop->func) )
		CallRuntimeFunction_bool_SetBoolValue( rt , out_obj , TRUE );
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "[%s]!=[%s]=>[false]" , GetFullFunctionName(functionptr1_direct_prop->func) , GetFullFunctionName(functionptr2_direct_prop->func) )
		CallRuntimeFunction_bool_SetBoolValue( rt , out_obj , FALSE );
	}
	
	return 0;
}

ZlangSummarizeDirectPropertySizeFunction ZlangSummarizeDirectPropertySize_functionptr;
void ZlangSummarizeDirectPropertySize_functionptr( struct ZlangRuntime *rt , struct ZlangObject *obj , size_t *summarized_obj_size , size_t *summarized_direct_prop_size )
{
	SUMMARIZE_SIZE( summarized_direct_prop_size , sizeof(struct ZlangDirectProperty_functionptr) )
	return;
}

static struct ZlangDirectFunctions direct_funcs_functionptr =
	{
		ZLANG_OBJECT_functionptr ,
		
		ZlangCreateDirectProperty_functionptr ,
		ZlangDestroyDirectProperty_functionptr ,
		
		NULL ,
		ZlangToString_functionptr ,
		ZlangFromDataPtr_functionptr ,
		ZlangGetDataPtr_functionptr ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		ZlangCompare_functionptr_EGUAL_functionptr ,
		ZlangCompare_functionptr_NOTEGUAL_functionptr ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		NULL ,
		
		ZlangSummarizeDirectPropertySize_functionptr ,
	} ;

ZlangDirectFunction_functionptr_SetObjectPtr functionptr_SetObjectPtr;
int functionptr_SetObjectPtr( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject *master_obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	functionptr_direct_prop->obj = master_obj ;
	
	return 0;
}

ZlangDirectFunction_functionptr_GetObjectPtr functionptr_GetObjectPtr;
int functionptr_GetObjectPtr( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangObject **master_obj )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	if( IsObjectPropertiesEntityNull(obj) )
		(*master_obj) = NULL ;
	else
		(*master_obj) = functionptr_direct_prop->obj ;
	
	return 0;
}

ZlangDirectFunction_functionptr_SetFunctionPtr functionptr_SetFunctionPtr;
int functionptr_SetFunctionPtr( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangFunction *func )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	if( ! IsTypeOf( rt , obj , GetFunctionPtrObjectInRuntimeObjectsHeap(rt) ) )
		return -1;
	
	functionptr_direct_prop->func = func ;
	
	return 0;
}

ZlangDirectFunction_functionptr_GetFunctionPtr functionptr_GetFunctionPtr;
int functionptr_GetFunctionPtr( struct ZlangRuntime *rt , struct ZlangObject *obj , struct ZlangFunction **func )
{
	struct ZlangDirectProperty_functionptr	*functionptr_direct_prop = GetObjectDirectProperty(obj) ;
	
	if( ! IsTypeOf( rt , obj , GetFunctionPtrObjectInRuntimeObjectsHeap(rt) ) )
		return -1;
	
	if( IsObjectPropertiesEntityNull(obj) )
		(*func) = NULL ;
	else
		(*func) = functionptr_direct_prop->func ;
	
	return 0;
}

ZlangImportObjectFunction ZlangImportObject_functionptr;
struct ZlangObject *ZlangImportObject_functionptr( struct ZlangRuntime *rt )
{
	struct ZlangObject	*obj = NULL ;
	struct ZlangFunction	*func = NULL ;
	int			nret = 0 ;
	
	nret = ImportObject( rt , & obj , ZLANG_OBJECT_functionptr , & direct_funcs_functionptr , sizeof(struct ZlangDirectFunctions) , NULL ) ;
	if( nret )
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_LINK_FUNC_TO_ENTITY , "import object to global objects heap" )
		DestroyObject( rt , obj );
		return NULL;
	}
	
	/* functionptr.GetObjectName() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetObjectName" , "GetObjectName()" , ZlangInvokeFunction_functionptr_GetObjectName , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* functionptr.GetFunctionName() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetFunctionName" , "GetFunctionName()" , ZlangInvokeFunction_functionptr_GetFunctionName , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* functionptr.GetFullFunctionName() */
	func = AddFunctionAndParametersInObject( rt , obj , "GetFullFunctionName" , "GetFullFunctionName()" , ZlangInvokeFunction_functionptr_GetFullFunctionName , ZLANG_OBJECT_string , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* functionptr.FindFunction(...) */
	func = AddFunctionAndParametersInObject( rt , obj , "FindFunction" , "FindFunction(string)" , ZlangInvokeFunction_functionptr_FindFunction_string , ZLANG_OBJECT_functionptr , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	/* functionptr.SetFunction(...) */
	func = AddFunctionAndParametersInObject( rt , obj , "SetFunction" , "SetFunction(string)" , ZlangInvokeFunction_functionptr_SetFunction_string , ZLANG_OBJECT_bool , ZLANG_OBJECT_string,NULL , NULL ) ;
	if( func == NULL )
		return NULL;
	
	SetRuntimeFunction_functionptr_SetObjectPtr( rt , functionptr_SetObjectPtr );
	SetRuntimeFunction_functionptr_GetObjectPtr( rt , functionptr_GetObjectPtr );
	SetRuntimeFunction_functionptr_SetFunctionPtr( rt , functionptr_SetFunctionPtr );
	SetRuntimeFunction_functionptr_GetFunctionPtr( rt , functionptr_GetFunctionPtr );
	
	return obj ;
}

